package com.wh.wisdomsite.xbox.server.util;

import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.wh.wisdomsite.xbox.ba.entity.Menu;
import com.wh.wisdomsite.xbox.ba.entity.SysLog;
import com.wh.wisdomsite.xbox.ba.service.IMenuService;
import com.wh.wisdomsite.xbox.ba.service.ISysLogService;
import com.wh.wisdomsite.xbox.server.manager.MenuMapManager;
import com.wh.wisdomsite.xbox.us.entity.User;
import com.wh.wisdomsite.xbox.utils.StringUtils;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.core.MethodParameter;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 日志工具类
 *
 * @version V1.0
 * @Package: com.wh.wisdomsite.xbox.server.util
 * @author: 丁奕
 * @date: 2018-10-29 16:10
 * @Copyright 公司版权所有
 * @Company 贵州万华科技有限公司Copyright (c) 2016
 **/
public class LogUtils {

    private static ISysLogService iSysLogService = (ISysLogService)ApplicationUtil.getBean("sysLogService");
    private static IMenuService iMenuService = (IMenuService)ApplicationUtil.getBean("menuService");

    /**
     * 保存日志
     */
    public static void saveLog(HttpServletRequest request, Object handler, Exception ex, String title){
        User user = UserUtils.getCurrentUser();
        if (user != null && user.getUsId()!= null){
            SysLog log = new SysLog();
            log.setTitle(title);
            log.setType(null);
            log.setRemoteAddr(StringUtils.getRemoteAddr(request));
            log.setUserAgent(request.getHeader("user-agent"));
            log.setReqUrl(request.getRequestURI());
            Map<String, String[]> parameterMap = request.getParameterMap();
            JSONObject jsonMap = JSONObject.fromObject(parameterMap);
            log.setParams(parameterMap);
            log.setMethod(request.getMethod());
            // 异步保存日志
            new SaveLogThread(log, handler, ex, user, jsonMap).start();
        }
    }

    /**
     * 保存日志线程
     */
    public static class SaveLogThread extends Thread{

        private SysLog log;
        private Object handler;
        private Exception ex;
        private User user;
        private Object parameterMap;

        public SaveLogThread(SysLog log, Object handler, Exception ex,User user,Object parameterMap){
            super(SaveLogThread.class.getSimpleName());
            this.log = log;
            this.handler = handler;
            this.ex = ex;
            this.user = user;
            this.parameterMap = parameterMap;
        }

        @Override
        public void run() {
            // 获取日志标题
            if (StringUtils.isBlank(log.getTitle())){
                String permission = "";
                if (handler instanceof HandlerMethod){
                    Method m = ((HandlerMethod)handler).getMethod();
                    RequiresPermissions rp = m.getAnnotation(RequiresPermissions.class);
                    permission = (rp != null ? org.apache.commons.lang3.StringUtils.join(rp.value(), ",") : "");
                    //根据权限标识设置菜单类型
                    if(permission != null && !permission.equals("")){
                        if(permission.substring(permission.length()-4).equals("page")){
                            log.setType(SysLog.TYPE_PAGE);
                        }else{
                            if(permission.substring(permission.length()-4).equals("edit")){
                                String pkId = findPkId((HandlerMethod)handler,(Map<String, String[]>)parameterMap);
                                //若pkId不为空，则是修改操作。若为空，则是添加操作
                                if(pkId == null || pkId.equals("")){
                                    permission = permission.replace("_edit","_add");
                                }
                            }
                            log.setType(SysLog.TYPE_BUTTON);
                        }
                    }
                }
                log.setSlCode(permission);
                log.setTitle(getMenuNamePath(permission));
            }
            // 如果有异常，设置异常信息
            log.setException(ExceptionUtils.getStackTraceAsString(ex));
            // 如果无标题并无异常日志，则不保存信息
            if (StringUtils.isBlank(log.getTitle()) && StringUtils.isBlank(log.getException())){
                return;
            }
            // 保存日志信息
            log.setSlId(UUID.randomUUID().toString().replace("-",""));
            log.setCreateBy(user.getUsId());
            log.setCreateDate(new Date());
            iSysLogService.insert(log);
        }
    }

    /**
     * 获取菜单名称路径（如：系统设置-机构用户-用户管理-编辑）
     */
    public static String getMenuNamePath(String permission){
        @SuppressWarnings("unchecked")
        Map<String, Menu> menuMap = MenuMapManager.getMenuMap();
        //若内存menuMap为空
        if (menuMap == null){
            menuMap = new HashMap<>();
            // 读取用户表中数据，存放入内存中用map管理
            EntityWrapper<Menu> ew = new EntityWrapper<>();
            ew.setEntity(new Menu());
            List<Menu> menuList = iMenuService.selectList(ew);
            if(menuList != null && !menuList.isEmpty()){
                for (Menu menu : menuList){
                    MenuMapManager.updateMenuToMap(menu);
                }
            }
            menuMap = MenuMapManager.getMenuMap();
        }
        //根据权限标识获取menu
        Menu menu = MenuMapManager.getMenuInMap(permission);
        String menuNamePath = "";
        List<String> menuNameList = new ArrayList<>();
        if (menu != null){
            //递归查找，如果该菜单仍有上级菜单，则继续向名称LIST中添加
            menuNameList = getNameList(menuNameList,menuMap,menu);
            if(menuNameList != null && !menuNameList.isEmpty()){
                Collections.reverse(menuNameList);
                menuNamePath = org.apache.commons.lang3.StringUtils.join(menuNameList, "-");
            }
        }
        return menuNamePath;
    }

    private static List<String> getNameList(List<String> menuNameList, Map<String, Menu> menuMap, Menu menu){
        //将菜单名称放入menuNameList
        menuNameList.add(menu.getName());
        //判断菜单是否有上级菜单，有则继续递归
        if(!menu.getParentId().equals("0")){
            menuNameList = getNameList(menuNameList,menuMap,menuMap.get(menu.getParentId()));
        }
        return menuNameList;
    }

    /**
     * 查找主键ID
     * @param handlerMethod
     * @param parameterMap
     * @return
     */
    private static String findPkId(HandlerMethod handlerMethod, Map<String, String[]> parameterMap){
        String pkId = null;
        //获取hanlder中的所有parameters
        MethodParameter[] parameters = handlerMethod.getMethodParameters();
        String pkIdKey = null;
        TableId annotation = null;
        //遍历parameters，对每一个parameter的类的属性进行判断，如果该属性是带有TableId注解的，则是主键
        for(MethodParameter parameter : parameters){
            Class clazz = parameter.getParameterType();
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields){
                annotation = field.getAnnotation(TableId.class);
                if(annotation != null){
                    pkIdKey = field.getName();
                    break;
                }
            }
            if(annotation != null){
                break;
            }
        }
        if(pkIdKey != null){
            JSONObject jsonMap = JSONObject.fromObject(parameterMap);
            pkId = (String)((JSONArray)jsonMap.get(pkIdKey)).get(0);
        }
        return pkId;
    }

}
